#include "swarmSocketServer.h"
swarmNetworkException::swarmNetworkException(string s)
{
	message = s;
}
const char* swarmNetworkException::what() const throw()
{
	return "Swarm Network Exception";
}
swarmNetworkException::~swarmNetworkException() throw() {}
string swarmNetworkException::getMessage() const
{
	return message;
}
using namespace std;

     int
     make_socket (uint16_t port)
     {
       int sock;
       struct sockaddr_in name;
     
       /* Create the socket. */
       sock = socket (PF_INET, SOCK_STREAM, 0);
       if (sock < 0)
         {
           ////perror ("socket");
           //exit (EXIT_FAILURE);
         }
     	int option = 1;
	if(setsockopt(sock,SOL_SOCKET,/*(SO_REUSEPORT | SO_REUSEADDR)*/ SO_REUSEADDR,(char*)&option,sizeof(option)) < 0)
	{
		////perror("setsockopt failed:");
	}
       /* Give the socket a name. */
       name.sin_family = AF_INET;
       name.sin_port = htons (port);
       name.sin_addr.s_addr = htonl (INADDR_ANY);
	int z = bind (sock, (struct sockaddr *) &name, sizeof (name));
       if (z < 0)
         {
           ////perror ("bind");
	   ////cout << "bind " << z << " errno " << errno << endl;
	   ////perror("bind :");
           //exit (EXIT_FAILURE);
         }
     
       return sock;
     }
//end added code

int read_from_client (int filedes, vector<vector<string> >& ms)
{
	struct sockaddr_in clientname;
	socklen_t len = sizeof(clientname);
	getpeername(filedes, (struct sockaddr *)&clientname, &len);
	char buffer[MAXMSG];
	char buffy[4] = "Ack";
	char buf[INET_ADDRSTRLEN];
	time_t rawtime;
	time (&rawtime);
	inet_ntop(AF_INET, &clientname, buf, INET_ADDRSTRLEN);
	vector<string> s;
	int nbytes;
	//if(!sync)
	//{
		fcntl(filedes, F_SETFL, fcntl(filedes, F_GETFL) | O_NONBLOCK);
	//}
	nbytes = read (filedes, buffer, MAXMSG);
	if (nbytes < 0)
	{
		/* Read error. */
		////perror ("read");
		//exit (EXIT_FAILURE);
		return 0;
	}
	else if (nbytes == 0)
	{
		//fprintf (stderr, "%ired2", nbytes);
		/* End-of-file. */
		return 0;//return -1;
	}
	else
	{
		/* Data read. */
		//fprintf (stderr, "Server: got message: `%s'\n", buffer);
		s.push_back(buffer);
		s.push_back(inet_ntoa(clientname.sin_addr));
		s.push_back(ctime(&rawtime));
		ms.push_back(s);
		nbytes = write(filedes, buffy, 5);
		//fprintf (stderr, "Server: got message: `%i'\n", nbytes);
		return 0;
	}
}
swarmSocketServer::swarmSocketServer(int pt)
{
	this->pt = pt;
	//this->sync = sync;
	extern int make_socket (uint16_t port);
	
	
	sock = make_socket (pt);
	
       	if (listen (sock, 1) < 0)
         {
		throw swarmNetworkException("could not make socket");
           ////perror ("listen");
           //exit (EXIT_FAILURE);
         }
	//fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | SO_REUSEADDR);
	
	
     	//if(!sync)
	//{
		fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
		
	//}
       /* Initialize the set of active sockets. */
       FD_ZERO (&active_fd_set);
       FD_SET (sock, &active_fd_set);
       //fprintf(stdout, "constructed\n");
}

bool swarmSocketServer::check()
{
	return true;
}
vector<vector<string> > swarmSocketServer::read(int sec, int usec)
{
	vector<vector<string> > messages;
	/* Block until input arrives on one or more active sockets. */
           read_fd_set = active_fd_set;
	if(sec < 0 || usec < 0)
	{
		if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
             {
              // //perror ("select");
              // exit (EXIT_FAILURE);
             }	
	}
	else
	{
		tv.tv_sec = sec;
		tv.tv_usec = usec;
	
           	if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &tv) < 0)
             	{
              		////perror ("select");
              	// exit (EXIT_FAILURE);
             	}
	}
	
     
           /* Service all the sockets with input pending. */
           for (int i = 0; i < FD_SETSIZE; ++i)
             if (FD_ISSET (i, &read_fd_set))
               {
                 if (i == sock)
                   {
                     /* Connection request on original socket. */
                     int newish;
                     size = sizeof (clientname);
                     newish = accept (sock,
                                   (struct sockaddr *) &clientname,
                                   &size);
                     if (newish < 0)
                       {
                         ////perror ("accept");
                         //exit (EXIT_FAILURE);
                       } else{
                     /*fprintf (stderr,
                              "Server: connect from host %s, port %hd.\n",
                              inet_ntoa (clientname.sin_addr),
                              ntohs (clientname.sin_port));*/
                     FD_SET (newish, &active_fd_set);
			}
                   }
                 else
                   {
                     /* Data arriving on an already-connected socket. */
                     if (read_from_client (i, messages) < 0)
                       {
			 ////perror("read already");
                         close (i);
                         FD_CLR (i, &active_fd_set);
			
                       }
                   }
               }
	return messages;
}
swarmSocketServer::~swarmSocketServer()
{
	close (sock);
}








